package com.yungu.swift.order.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.yungu.swift.assets.driver.model.dto.CarModelDto;
import com.yungu.swift.assets.driver.service.CarModelService;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.constants.CommonConstant;
import com.yungu.swift.constants.OrderConstant;
import com.yungu.swift.order.config.ApplicationConfig;
import com.yungu.swift.order.dao.OrderMapper;
import com.yungu.swift.order.model.dto.OrderDetailDto;
import com.yungu.swift.order.model.dto.OrderDto;
import com.yungu.swift.order.model.dto.OrderOperateLogDto;
import com.yungu.swift.order.model.param.JoinOrderParam;
import com.yungu.swift.order.service.OrderDetailService;
import com.yungu.swift.order.service.OrderOperateLogService;
import com.yungu.swift.order.service.OrderRiskControlService;
import com.yungu.swift.system.sys.model.dto.SysWayDto;
import com.yungu.swift.utils.DateUtils;
import com.yungu.swift.utils.MapUtils;
import com.yungu.swift.utils.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.yungu.swift.order.model.enums.OrderErrorEnum.*;

/**
 * @author : cuixiuyin
 * @date : 2019/6/5
 */
@Service
public class OrderRiskControlServiceImpl implements OrderRiskControlService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderOperateLogService orderOperateLogService;
    @Reference
    private CarModelService carModelService;

    @Override
    public ResponseData<Boolean> canPasCreateOrder(String pasUuid, String appid, Integer typeModule, String actualPassengerMobile, Integer typeTime) {
        Map params = MapUtils.build(10);
        //客服电话
        String serviceTel = ApplicationConfig.COMMON_CONFIG.getServiceTel();
        //查看是否有待支付订单
        params.put("passengerUuid", pasUuid);
        params.put("appid", appid);
        //待支付 跨城订单与专快订单分开判断
        if (typeModule != null && (typeModule == CommonConstant.BUSINESS_TYPE_POOL || typeModule == CommonConstant.BUSINESS_TYPE_PARCEL)) {
            params.put("joinStatus", OrderConstant.ORDER_JOIN_STATUS_PASSENGER_PAY);
            params.put("closeStatus", OrderConstant.ORDER_CLOSE_STATUS_NORMAL);
        } else {
            params.put("mainStatus", OrderConstant.ORDER_MAIN_STATUS_DONE);
        }

        List<OrderDto> toBePayedlist = orderMapper.list(params);
        if (CollectionUtils.isNotEmpty(toBePayedlist)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "有待支付的订单");
        }
        //查看是否有进行中的订单，规则：大于5单则不能发单
        params.clear();
        params.put("passengerUuid", pasUuid);
        params.put("appid", appid);
        List<OrderDto> doingList = orderMapper.findPasDoingOrder(params);
        if (doingList.size() > 4) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "进行中的订单数不能超过5单");
        }
        //检查是否最近15分钟取消成功订单超过3次
        params.clear();
        params.put("passengerUuid", pasUuid);
        params.put("appid", appid);
        List<OrderDto> lastCancelOrderList = orderMapper.getLastCancelOrderByPassengerDistributed(params);
        if (null != lastCancelOrderList && lastCancelOrderList.size() >= 3) {
            Date oFirstTime = lastCancelOrderList.get(2).getDistributeTime();
            Date oLastTime = lastCancelOrderList.get(0).getDistributeTime();
            //则判断间隔是否在15分钟内：是则限制，否则放开
            if ((System.currentTimeMillis() - oFirstTime.getTime()) <= 1000 * 60 * 15) {
                String sustainTime = DateUtils.format(new Date(oLastTime.getTime() + 1000 * 15 * 60), "HH:mm");
                String msg = "由于你多次取消订单，暂时无法再叫单，请于" + sustainTime + "后再尝试；感谢您的使用，详情可致电：" + serviceTel;
                return ResponseData.buildErrorResponse(ERR_CODE_CANCEL_RESTRICT_RULE.getCode(), msg);
            }
        }
        //加条件判断不能再叫自己的即时单
        if (typeTime != null && CommonConstant.TYPE_TIME_REAL_TIME == typeTime) {
            params.clear();
            params.put("selfOrder", 1);
            params.put("actualPassengerMobile", actualPassengerMobile);
            params.put("passengerUuid", pasUuid);
            params.put("appid", appid);
            List<OrderDto> findPasDoingOrder = orderMapper.findPasDoingOrder(params);
            if (CollectionUtils.isNotEmpty(findPasDoingOrder)) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "您未结束上个行程，无法再叫单");
            }
        }
        return ResponseData.buildSuccessResponse("乘客符合下单条件", Boolean.TRUE);
    }


    @Override
    public ResponseData<Boolean> driverHasGoingOrder(String driverUuid, Date departTime) {
        Map<String, Object> paramMap = MapUtils.build(3);
        paramMap.put("driverUuid", driverUuid);
        paramMap.put("departTime", departTime == null ? System.currentTimeMillis() : departTime.getTime());
        List<OrderDto> orderDtoList = orderMapper.driverHasGoingOrder(paramMap);
        if (driverUuid != null && !orderDtoList.isEmpty()) {
            if (orderDtoList.get(0).getTypeTime() == 1) {
                return ResponseData.buildErrorResponse(GRAB_ERROR_4016.getCode(), GRAB_ERROR_4016.getMsg());
            }
            return ResponseData.buildErrorResponse(GRAB_ERROR_1004.getCode(), GRAB_ERROR_1004.getMsg());
        }
        return ResponseData.buildSuccessResponse("司机状态正常", Boolean.TRUE);
    }

    @Override
    public ResponseData<List<OrderDto>> driverHasGoingOrder(Map<String, Object> params) {
        List<OrderDto> list = this.orderMapper.queryDriDoingOrder(params);
        if (list.size() > 0) {
            return ResponseData.buildSuccessResponse("查询成功", list);
        }
        return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "没有进行中的订单");
    }


    @Override
    public ResponseData<Boolean> driverHasRealTimeJoinOrder(String driverUuid) {
        Map<String, Object> params = MapUtils.build(8);
        params.put("actualDriverUuid", driverUuid);
        params.put("typeTime", CommonConstant.TYPE_TIME_REAL_TIME);
        params.put("typeMain", OrderConstant.ORDER_TYPE_MAIN);
        return ResponseData.buildSuccessResponse(CollectionUtils.isNotEmpty(this.orderMapper.findDriDoing(params)));
    }

    @Override
    public ResponseData<Boolean> driverHasRealTimeOrder(String driverUuid) {
        return ResponseData.buildSuccessResponse(CollectionUtils.isEmpty(orderMapper.driverHasRealTimeOrder(driverUuid)));
    }

    @Override
    public ResponseData<Boolean> isValidOrder(String orderUuid, String driverUuid) {
        Map<String, Object> map = MapUtils.build(4);
        map.put("orderUuid", orderUuid);
        map.put("driverUuid", driverUuid);
        return ResponseData.buildSuccessResponse(orderMapper.isValidOrder(map) > 0);
    }

    @Override
    public ResponseData<String> overTimeExceptionHandling(String appid) {
        //查询异常订单：查询前一天并且创建时间距离超过30分钟，未派到单的订单（100）不包含拼车业务
        List<OrderDto> orderDtos = orderMapper.getOverTimeExceptionList();
        if (orderDtos.size() == 0) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "异常订单处理：没有需要处理的异常订单");
        }
        String reason = "订单异常，系统关闭";
        StringBuilder successMsg = new StringBuilder();
        successMsg.append("处理异常订单号：");
        StringBuilder failMsg = new StringBuilder();
        failMsg.append("处理失败的订单号：");
        //因为异常的订单不多，不采用批量处理
        for (OrderDto orderDto : orderDtos) {
            try {
                //状态验证
                Integer preMainStatus = orderDto.getMainStatus();
                Integer preSubStatus = orderDto.getSubStatus();
                if (!preMainStatus.equals(OrderConstant.ORDER_MAIN_STATUS_INITIAL)
                        && !preSubStatus.equals(OrderConstant.ORDER_STATUS_WAIT)) {
                    continue;
                }
                //修改订单
                orderDto.setMainStatus(OrderConstant.ORDER_MAIN_STATUS_CANCEL);
                orderDto.setSubStatus(OrderConstant.ORDER_STATUS_CLOSE);
                orderDto.setUpdateOn(new Date());
                orderMapper.edit(orderDto);
                //修改订单详情
                Map params = MapUtils.build();
                params.put("orderUuid", orderDto.getUuid());
                OrderDetailDto orderDetailDto = (OrderDetailDto) orderDetailService.get(params).getData();
                orderDetailDto.setUpdateOn(new Date());
                orderDetailDto.setCloseTime(new Date());
                orderDetailDto.setCloseReason(reason);
                orderDetailService.edit(orderDetailDto);
                //新增订单操作记录
                OrderOperateLogDto logDto = new OrderOperateLogDto();
                logDto.setUuid(StringUtils.buildUUID());
                logDto.setOrderUuid(orderDto.getUuid());
                logDto.setAppid(orderDto.getAppid());
                logDto.setType(OrderOperateLogDto.TYPE_CLOSE);
                logDto.setPreMainStatus(preMainStatus);
                logDto.setPreSubStatus(preSubStatus);
                logDto.setNowMainStatus(orderDto.getMainStatus());
                logDto.setNowSubStatus(orderDto.getSubStatus());
                logDto.setCreateOn(new Date());
                logDto.setAppid(orderDto.getAppid());
                logDto.setReason(reason);
                orderOperateLogService.add(logDto);
                successMsg.append(orderDto.getUuid());
                successMsg.append(",");
            } catch (Exception e) {
                e.printStackTrace();
                failMsg.append(orderDto.getUuid());
                failMsg.append(",");
            }
        }
        return ResponseData.buildSuccessResponse(successMsg.append(failMsg.toString()).toString());
    }

    @Override
    public ResponseData<Boolean> verifyParcelBusiness(JoinOrderParam joinOrderParam, SysWayDto sysWayDto) {
        /*出发时间验证*/
        if (joinOrderParam.getDeparTime() == null) {
            joinOrderParam.setDeparTime(new Date());
        }
        if (joinOrderParam.getDeparTime().before(new Date())) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "出发时间不能小于当前时间");
        }
        //线路运营时间判断
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDate localDate = LocalDateTime.ofInstant(joinOrderParam.getDeparTime().toInstant(), zoneId).toLocalDate();
        Instant startInstant = LocalDateTime.ofInstant(sysWayDto.getStartTime().toInstant(), zoneId).toLocalTime().atDate(
                localDate).atZone(zoneId).toInstant();
        Date start = Date.from(startInstant);
        Instant endInstant = LocalDateTime.ofInstant(sysWayDto.getEndTime().toInstant(), zoneId).toLocalTime().atDate(
                localDate).atZone(zoneId).toInstant();
        Date end = Date.from(endInstant);
        if (joinOrderParam.getDeparTime().before(start) || joinOrderParam.getDeparTime().after(end)) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "非路线运营时间");
        }
        //是否开通跨城小件业务
        if (!CommonConstant.STATUS_OPENED.equals(sysWayDto.getParcelStatus())) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "该线路业务暂未开通");
        }
        //判断能否下单
        ResponseData<Boolean> result = canPasCreateOrder(joinOrderParam.getPassengerDto().getUuid(), joinOrderParam.getAppid(),
                CommonConstant.BUSINESS_TYPE_POOL, joinOrderParam.getPassengerDto().getMobile(), null);
        if (!result.isSuccess()) {
            return result;
        }
        //获取车型
        ResponseData<CarModelDto> carmodelRsd = carModelService.get(MapUtils.build("businessType", CommonConstant.BUSINESS_TYPE_PARCEL));
        if (!carmodelRsd.isSuccess()) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "估价失败：获取车型信息失败");
        }
        joinOrderParam.setCarModelUuid(carmodelRsd.getData().getUuid());

        return ResponseData.buildSuccessResponse("校验通过", Boolean.TRUE);
    }
}
